<?php

namespace common\service;

use bonza\fdd\Fdd;
use common\exception\LogicException;
use common\model\TenantAuthenticationModel;
use common\model\TenantModel;
use common\model\UserAuthenticationModel;
use common\model\UserModel;
use support\ErrorCode;
use think\Exception;
use think\exception\HttpResponseException;
use think\Response;

class FDDService
{

    /**
     * 法大大接口授权配置
     * @var \bonza\fdd\Fdd
     */
    protected $fddObj;

    /**
     * FDDService constructor.
     */
    public function __construct()
    {
        // 实例化法大大接口对象
        $fddConfig = C('fdd');
        $this->fddObj = new Fdd($fddConfig);
    }


    /**
     * 处理法大大接口异常
     * @param $fddResult
     */
    protected function handleException($fddResult)
    {
        if (!in_array((int)$fddResult['code'], [1, 2])) {
            trace("error: {$fddResult['code']}, {$fddResult['msg']}" . var_export($fddResult, true), 'ERR');
            throw_strack_exception("error: {$fddResult['code']}, {$fddResult['msg']}", ErrorCode::FDD_INTERFACE_EXCEPTION);
        }
    }

    /**
     * 抛出http状态码异常
     * @param $message
     * @param int $code
     * @param int $httpCode
     */
    protected function throwHttpStatusException($message, $code = 500, $httpCode = 500)
    {
        $errorData = [
            "code" => $code,
            "msg" => $message,
        ];
        $response = new Response(json_encode($errorData), $httpCode);
        throw new HttpResponseException($response);
    }


    /**
     * 获取租户实名认证链接（未实名认证的才调用本接口）
     * @param $param
     * @return false|string
     * @throws Exception
     */
    public function getTenantRealNameAuthUrl($param)
    {
        $tenantId = $param['tenant_id'];
        $reNew = $param['re_new'] ?? "no";
        $tenantModel = model(TenantModel::class);
        $tenantAuthenticationModel = model(TenantAuthenticationModel::class);

        $optionService = new OptionsService();
        $mediaServiceOption = $optionService->getMediaUploadServer();
        if (empty($mediaServiceOption)) {
            throw_strack_exception("missing media service option", ErrorCode::MISSING_MEDIA_SERVICE_OPTION);
        }

        $tenant = $tenantModel->find($tenantId);


        $tenantAuthenticationService = new TenantAuthenticationService();

        $tenantAuthentication = $tenantAuthenticationService->find([
            "filter" => [
                'tenant_id' => $tenantId
            ]
        ]);


        if (empty($tenant)) {
            throw_strack_exception("missing tenant info", ErrorCode::MISSING_TENANT_INFO);
        }
        if (empty($tenantAuthentication)) {
            throw_strack_exception("missing tenant authentication info", ErrorCode::MISSING_TENANT_AUTHENTICATION_INFO);
        }
        if ($tenantAuthentication['tenant_authentication']['status'] != "active") {
            throw_strack_exception("tenant authentication did not pass the audit", ErrorCode::TENANT_AUTHENTICATION_FAILED);
        }


        $fddCustomerId = $tenant['fdd_customer_id'];
        if (empty($tenant['fdd_customer_id'])) {

            // 处理完返回参数

            /**
             * 1、注册供应商信息到法大大，已经存在可以法大大会忽略
             *
             * {
             *    "code": 1,
             *    "data": "CB80F88A4B6E677CF58238F5BE310969", //注册成功返回的customer_id客户编号是用户在法大大的唯一标识，存入租户表 fdd_customer_id
             *    "msg": "success"
             * }
             *
             */

            $registerData = $this->fddObj->accountRegister('tent_' . $tenantId, 2);
            // 错误处理
            $this->handleException($registerData);
            $fddCustomerId = $registerData['data'];
            $tenantModel->modifyItem([
                'id' => $tenantId,
                'fdd_customer_id' => $fddCustomerId
            ]);
        }

        if (!empty($tenantAuthentication['tenant_authentication']['fdd_auth_url']) && $reNew == "no") {
            return base64_decode($tenantAuthentication['tenant_authentication']['fdd_auth_url']);
        }


        /**
         * 2、供应商通过法大大实名认证
         *
         * 法人信息：
         * {
         *     "legal_name" : "张三" //法人姓名（必须）
         *     "legal_id"   : "430701202005056666" // 法人身份证号 （必须）
         *     "legal_mobile"   : "18888888888" // 法人手机证号（必须）
         *     "legal_id_front_path"   : "xxx" // 法人证件正面照下载地址（必须）
         *     "bank_card_no" : "" // 法人银行卡号 （本平台不需要）
         * }
         *
         * 返回信息
         * {
         * "code": 1,
         *     "data": {
         *     "transactionNo": "ce304fa1d6044cb4b8176e457f193deb", // verified_serialno 写入租户认证表
         *     "url": "aHR0cHM6Ly9yZWFsbmFtZXZlcmlmeS10ZXN0LmZhZGFkYS5jb20vZmRkQXV0aGVudGljYXRpb25TZXJ2aWNlL3YxL2FwaS9zeW5zQXV0aGVudGljYXRpb24uYWN0aW9uP3RyYW5zYWN0aW9uX25vPTlBODY5RjE0RjY5MzI2RjIyOTVBMkUyMDU4NkE2MzFEODczNjlEQjAyRTA5NkMzQUQxN0NDRTc4NUM2RDIwOEJGNzU3Q0QwNjAyN0YzODA3JnNpZ249T0VaRlJUaEZORVpHT1VVeU5qSkdOelF6TmtFek5EVXlSa1F6TjBSR05UVTFOek16UlRWQk5nPT0mYXBwX2lkPTQwMzgwMiZ0aW1lc3RhbXA9MTYwMzI2OTYzNDk1OA==" 写入租户认证表
         *  },
         * "msg": "success"
         * }
         *
         * url 实名认证链接需要 base64_decode 解密
         */

        // 营业执照
        $mediaBusinessLicenseThumb = $tenantAuthentication['media_business_license']['thumb'];

        // 法人身份证正面
        $mediaFrontOfLegalIdThumb = $tenantAuthentication['media_front_of_legal_id']['thumb'];

        /**
         *
         *
         *
         * cert_flag =1 认证成功后自动申 请实名证书 参数值为“0”：不申请 参数值为“1”：自动申请
         */
        $extraParam = [
            'page_modify' => "2",
            'cert_flag' => "1",
            'company_info' => json_encode([
                'company_name' => $tenantAuthentication['tenant_authentication']['company_name'],
                'credit_no' => $tenantAuthentication['tenant_authentication']['unified_social_credit_code'],
                'credit_image_path' => $mediaBusinessLicenseThumb,
            ]),
            'bank_info' => json_encode([
                'bank_name' => $tenantAuthentication['tenant_authentication']['bank_of_deposit'],
                'bank_id' => $tenantAuthentication['tenant_authentication']['bank_account'],
                'subbranch_name' => $tenantAuthentication['tenant_authentication']['bank_subbranch'],
            ]),
            'legal_info' => json_encode([
                'legal_name' => $tenantAuthentication['tenant_authentication']['legal_person_name'],
                'legal_id' => $tenantAuthentication['tenant_authentication']['legal_id_number'],
                'legal_mobile' => $tenantAuthentication['tenant_authentication']['legal_phone'],
                'legal_id_front_path' => $mediaFrontOfLegalIdThumb,
//                'bank_card_no'
            ]),

        ];
        $verifyData = $this->fddObj->getCompanyVerifyUrl($fddCustomerId, C("fdd.callBackUrl"), $extraParam, 2, 1, ['m_verified_way' => 1]);
        // 错误处理
        $this->handleException($verifyData);


        // 存储 transactionNo

        $tenantAuthenticationModel->modifyItem([
            'id' => $tenantAuthentication['tenant_authentication']['id'],
            'fdd_transaction_no' => $verifyData['data']['transactionNo'],
            'fdd_auth_url' => $verifyData['data']['url']
        ]);


        return base64_decode($verifyData['data']['url']);
    }

    /**
     * 生成证书
     * @param $customerId
     * @param $verifiedSerialNo
     */
    public function generateCertificate($customerId, $verifiedSerialNo)
    {
        return $this->fddObj->applyCert($customerId, $verifiedSerialNo);
    }


    /**
     * 上传合同模板（平台）
     */
    public function uploadContractTemplate($data)
    {
        return $this->fddObj->uploadTemplate();
    }


    /**
     * 查询合同模板
     */
    public function selectContractTemplateList()
    {

    }

    /**
     * 查看合同
     */
    public function viewContract()
    {

    }


    /**
     * 签合同
     */
    public function signContract()
    {

    }

    /**
     * 认证回调
     * @param $param
     * @return bool
     * @throws \think\Exception
     */
    public function authCallBack($param)
    {
        APP_DEBUG && trace("FDD auth callback got in", 'INFO');
        APP_DEBUG && trace(json_encode($param), 'INFO');
        $verifyFlag = $this->fddObj->verifySign($param);
        if (!$verifyFlag) {
            $this->throwHttpStatusException("sign error", 400, 400);
        }

        try {
            $res = true;
            if ($param['authenticationType'] == 1) {
                $res = $this->userAuthCallback($param);
                // 个人 todo 个人认证回调
            } else if ($param['authenticationType'] == 2) {
                // 企业
                $res = $this->tenantAuthCallback($param);
            }
            return $res;
        } catch (HttpResponseException $e) {
            trace($e->getMessage() . PHP_EOL . $e->getTraceAsString() . PHP_EOL, 'ERR');
            throw $e;
        } catch (\Throwable $e) {
            trace($e->getMessage() . PHP_EOL . $e->getTraceAsString() . PHP_EOL, 'ERR');
            $this->throwHttpStatusException($e->getMessage(), $e->getCode(), 500);
        }
    }

    /**
     * 个人认证回调 业务处理
     * @param $param
     * @return bool
     * @throws \think\Exception
     */
    private function userAuthCallback($param)
    {
        // 个人认证状态修改 个人认证状态描述留存


        $customerId = $param['customerId'];
        $transactionNo = $param['serialNo'];

        $userModel = model(UserModel::class);
        $userAuthenticationModel = model(UserAuthenticationModel::class);
        $userData = $userModel->where(['fdd_customer_id' => $customerId])->find();

        if (empty($userData)) {
            throw new LogicException("can`t found related user", ErrorCode::NOT_FOUND_RELATED_USER);
        }

        $userModel->save([
            'id' => $userData['id'],
            'fdd_customer_id' => $customerId
        ]);

        $userAuthenticationData = $userAuthenticationModel->where(['user_id' => $userData['id']])->find();

        if (empty($userAuthenticationData)) {
            throw new LogicException("can`t found user authentication data", ErrorCode::USER_AUTHENTICATION_INFO_NOT_FOUND);
        }

        $userAuthenticationModel->save([
            'id' => $userAuthenticationData['id'],
            'fdd_auth_status' => $param['status'],
            'fdd_auth_status_desc' => $param['statusDesc'],
            'fdd_cert_status' => $param['certStatus'],
        ]);

        //0：未激活；
        //1：未认证；
        //2：审核通过；
        //3：已提交待审核；
        //4：审核不通过

        switch ((int)$param['status']) {
            case 0:
                // 未激活
                break;
            case 1:
                // 未认证
                break;
            case 2:
                // 审核通过
                //检查证书申请状态
                if ((int)$param['certStatus'] == 0) {
                    // 没有申请证书
                    // 自动申请
                    $this->generateCertificate($customerId, $transactionNo);
                    $userModel->save([
                        'id' => $userData['id'],
                        'is_identified' => "yes",
                    ]);
                }
                break;
            case 3:
                // 已提交待审核
                break;
            case 4:
                // 审核不通过
                break;
            default:
        }
        return true;
    }

    /**
     * 企业认证回调 业务处理
     * @param $param
     * @return bool
     * @throws Exception
     */
    private function tenantAuthCallback($param)
    {
        $customerId = $param['customerId'];
        $transactionNo = $param['serialNo'];
        $tenantModel = model(TenantModel::class);

        $tenant = $tenantModel->where([
            'fdd_customer_id' => $customerId,
        ])->find();
        if (empty($tenant)) {
            throw new LogicException("can`t found match tenant", ErrorCode::TENANT_NOT_EXIST);
        }

        $tenantAuthenticationModel = model(TenantAuthenticationModel::class);
        $tenantAuthentication = $tenantAuthenticationModel->where([
            'tenant_id' => $tenant['id'],
            'fdd_transaction_no' => $transactionNo,
        ])->find();
        if (empty($tenantAuthentication)) {
            throw new LogicException("missing auth transaction data", ErrorCode::MISSING_AUTH_TRANSACTION_DATA);
        }

        $tenantAuthenticationModel->modifyItem([
            'id' => $tenantAuthentication['id'],
            'fdd_auth_status' => $param['status'],
            'fdd_auth_status_desc' => $param['statusDesc'],
            'fdd_cert_status' => $param['certStatus'],
        ]);

        switch ((int)$param['status']) {
            case 0:
                // 未认证
                break;
            case 1:
                // 管理员资料已提交
                break;
            case 2:
                // 企业基本资料(没有申请表) 已提交
                break;
            case 3:
                // 已提交 待审核
                break;
            case 4:
                //审核通过

                // 修改租户为激活状态
                if ($tenant['status'] != 'active') {
                    $tenantModel->modifyItem(['id' => $tenant['id'], 'status' => 'active']);
                }
                //检查证书申请状态
                if ((int)$param['certStatus'] == 0) {
                    // 没有申请证书
                    // 自动申请
                    $this->generateCertificate($customerId, $transactionNo);
                }
                break;

            case 5:
                // 审核不通过
                break;
            case 6:
                // 人工初审通过
                break;
            default:
        }
        return true;
    }

    /**
     * 获取个人个人认证链接
     * @param $param
     * @return false|string
     */
    public function getUserRealNameAuthUrl($param)
    {
        $userId = $param['user_id'];
        $reNew = $param['re_new'] ?? "no";
        $userAuthenticationService = new UserAuthenticationService();
        $userModel = model(UserModel::class);
        $userData = $userModel->find($userId);
        $userAuthenticationData = $userAuthenticationService->find([
                'filter' => [
                    'user_id' => $userId
                ]
            ]
        );

        if (empty($userData)) {
            throw_strack_exception("missing user info", ErrorCode::USER_INFO_NOT_FOUND);
        }
        if (empty($userAuthenticationData)) {
            throw_strack_exception("missing user authentication info", ErrorCode::USER_AUTHENTICATION_INFO_NOT_FOUND);
        }
        $fddCustomerId = $userData['fdd_customer_id'];
        if (empty($fddCustomerId)) {

            // 处理完返回参数

            /**
             * 1、注册供应商信息到法大大，已经存在可以法大大会忽略
             *
             * {
             *    "code": 1,
             *    "data": "CB80F88A4B6E677CF58238F5BE310969", //注册成功返回的customer_id客户编号是用户在法大大的唯一标识，存入租户表 fdd_customer_id
             *    "msg": "success"
             * }
             *
             */

            $registerData = $this->fddObj->accountRegister('user_' . $userId, 1);

            // 错误处理
            $this->handleException($registerData);
            $fddCustomerId = $registerData['data'];
            $userModel->modifyItem([
                'id' => $userId,
                'fdd_customer_id' => $fddCustomerId,
            ]);
        }

        if (!empty($userAuthenticationData['user_authentication']['fdd_auth_url']) && $reNew == "no") {
            return base64_decode($userAuthenticationData['user_authentication']['fdd_auth_url']);
        }

        /**
         * 2、供应商通过法大大实名认证
         *
         * 法人信息：
         * {
         *     "legal_name" : "张三" //法人姓名（必须）
         *     "legal_id"   : "430701202005056666" // 法人身份证号 （必须）
         *     "legal_mobile"   : "18888888888" // 法人手机证号（必须）
         *     "legal_id_front_path"   : "xxx" // 法人证件正面照下载地址（必须）
         *     "bank_card_no" : "" // 法人银行卡号 （本平台不需要）
         * }
         *
         * 返回信息
         * {
         * "code": 1,
         *     "data": {
         *     "transactionNo": "ce304fa1d6044cb4b8176e457f193deb", // verified_serialno 写入租户认证表
         *     "url": "aHR0cHM6Ly9yZWFsbmFtZXZlcmlmeS10ZXN0LmZhZGFkYS5jb20vZmRkQXV0aGVudGljYXRpb25TZXJ2aWNlL3YxL2FwaS9zeW5zQXV0aGVudGljYXRpb24uYWN0aW9uP3RyYW5zYWN0aW9uX25vPTlBODY5RjE0RjY5MzI2RjIyOTVBMkUyMDU4NkE2MzFEODczNjlEQjAyRTA5NkMzQUQxN0NDRTc4NUM2RDIwOEJGNzU3Q0QwNjAyN0YzODA3JnNpZ249T0VaRlJUaEZORVpHT1VVeU5qSkdOelF6TmtFek5EVXlSa1F6TjBSR05UVTFOek16UlRWQk5nPT0mYXBwX2lkPTQwMzgwMiZ0aW1lc3RhbXA9MTYwMzI2OTYzNDk1OA==" 写入租户认证表
         *  },
         * "msg": "success"
         * }
         *
         * url 实名认证链接需要 base64_decode 解密
         */

        // 身份证正面
        $mediaFrontOfIdThumb = $userAuthenticationData['media_front_of_id']['thumb'];

        // 身份证反面
        $mediaReverseOfIdThumb = $userAuthenticationData['media_reverse_of_id']['thumb'];

        /**
         *
         *
         *
         * cert_flag =1 认证成功后自动申 请实名证书 参数值为“0”：不申请 参数值为“1”：自动申请
         */
        $extraParam = [
            'customer_name' => $userAuthenticationData['user_authentication']['real_name'],
            'customer_ident_no' => $userAuthenticationData['user_authentication']['id_number'],
            'mobile' => $userAuthenticationData['user_authentication']['phone'],
            'ident_front_path' => $mediaFrontOfIdThumb,
            'ident_back_path' => $mediaReverseOfIdThumb,

        ];

        // 认证方式 0 三元素标准方案
        $verifyAway = 1;
        // 是否允许修改
        $pageModify = 2;
        // 证书生成标识 1 自动生成
        $certFlag = 1;
        // 认证方式
        $customerIdentType = 0;

        $verifyData = $this->fddObj->getPersonVerifyUrl($fddCustomerId, C("fdd.callBackUrl"), $extraParam, $verifyAway, $pageModify, $certFlag, $customerIdentType);
        // 错误处理
        $this->handleException($verifyData);


        // 存储 transactionNo

        $userAuthenticationModel = model(UserAuthenticationModel::class);
        $userAuthenticationModel->modifyItem([
            'id' => $userAuthenticationData['user_authentication']['id'],
            'fdd_transaction_no' => $verifyData['data']['transactionNo'],
            'fdd_auth_url' => $verifyData['data']['url'],
        ]);


        return base64_decode($verifyData['data']['url']);
    }

    /**
     * 查询租户法大大证书信息
     * @param $tenantId
     * @return mixed
     */
    public function getTenantQueryCert($tenantId)
    {
        $tenantModel = model(TenantModel::class);
        $fddCustomerId = $tenantModel->where(['id' => $tenantId])->getField('fdd_customer_id');
        if (empty($fddCustomerId)) {
            throw_strack_exception("missing user authentication info", ErrorCode::USER_AUTHENTICATION_INFO_NOT_FOUND);
        }

        $queryCertData = $this->fddObj->queryCert($fddCustomerId);
        // 错误处理
        $this->handleException($queryCertData);

        return json_decode($queryCertData['data'], true);
    }

    /**
     * 查询授权状态
     * @param $fddCustomerId
     * @return mixed
     */
    public function getAuthStatus($fddCustomerId)
    {
        $data = $this->fddObj->beforeAuthSignStatus($fddCustomerId);
        $this->handleException($data);
        return $data['data'];
    }

    /**
     * 企业授权/取消授权给个人
     * @param $params
     * @return bool
     */
    public function authorization($params)
    {
        $tenantGrantService = new TenantGrantService();
        $tenantGrant = $tenantGrantService->getTenantGrant(['id' => $params['param']['id']]);
        $tenantService = new TenantService();
        $tenantCustomerId = $tenantService->getFddCustomerId(["id" => $tenantGrant['tenant_id']]);

        $userService = new UserService();
        $userCustomerId = $userService->getFddCustomerId(["id" => $tenantGrant['user_id']]);

        // $operation 0：取消授权， 1：授权
        $operation = $params['param']['operation'];

        $res = $this->fddObj->authorization($tenantCustomerId, $userCustomerId, $operation);

        if ($res['result'] == 'error') {
            throw_strack_exception("error: {$res['code']}, {$res['msg']}", ErrorCode::AUTHORIZATION_OPERATION_FAILED);
        }
        return $tenantGrantService->modifyTenantGrantStatus($tenantGrant['id'], $operation == 1 ? 'active' : "disabled");

    }
}
